// RUN: mlir-opt %s --transform-interpreter -allow-unregistered-dialect --split-input-file --verify-diagnostics | FileCheck %s

// UNSUPPORTED: target=aarch64-pc-windows-msvc

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    // expected-remark @below {{applying transformation}}
    transform.test_transform_op
    transform.yield
  }
}

// -----

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    %0 = transform.test_produce_self_handle_or_forward_operand { foo = "bar" } : () -> !transform.any_op
    // expected-remark @below {{succeeded}}
    transform.test_consume_operand_of_op_kind_or_fail %0, "transform.test_produce_self_handle_or_forward_operand" : !transform.any_op
    transform.yield
  }
}

// -----

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    %0 = transform.test_produce_self_handle_or_forward_operand { foo = "bar" } : () -> !transform.any_op
    // expected-error @below {{expected the operand to be associated a payload op of kind transform.sequence got transform.test_produce_self_handle_or_forward_operand}}
    transform.test_consume_operand_of_op_kind_or_fail %0, "transform.sequence" : !transform.any_op
    transform.yield
  }
}

// -----

// It is okay to have multiple handles to the same payload op as long
// as only one of them is consumed. The expensive checks mode is necessary
// to detect double-consumption.
module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    %0 = transform.test_produce_self_handle_or_forward_operand { foo = "bar" } : () -> !transform.any_op
    %1 = transform.test_copy_payload %0 : (!transform.any_op) -> !transform.any_op
    // expected-remark @below {{succeeded}}
    transform.test_consume_operand_of_op_kind_or_fail %0, "transform.test_produce_self_handle_or_forward_operand" : !transform.any_op
    transform.yield
  }
}

// -----

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    transform.sequence %arg0 : !transform.any_op failures(propagate) {
    ^bb0(%arg1: !transform.any_op):
      // expected-remark @below {{applying transformation "a"}}
      test_transform_op "a"
      // expected-remark @below {{applying transformation "b"}}
      test_transform_op "b"
      // expected-remark @below {{applying transformation "c"}}
      test_transform_op "c"
    }
    // expected-remark @below {{applying transformation "d"}}
    transform.test_transform_op "d"
    // expected-remark @below {{applying transformation "e"}}
    transform.test_transform_op "e"
    transform.yield
  }
}

// -----

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    %0 = transform.test_produce_self_handle_or_forward_operand : () -> !transform.any_op
    transform.sequence %0 : !transform.any_op failures(propagate) {
    ^bb0(%arg1: !transform.any_op):
      // expected-remark @below {{succeeded}}
      test_consume_operand_of_op_kind_or_fail %arg1, "transform.test_produce_self_handle_or_forward_operand" : !transform.any_op
    }
    transform.yield
  }
}

// -----

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    %0 = transform.sequence %arg0 : !transform.any_op -> !transform.any_op failures(propagate) {
    ^bb0(%arg1: !transform.any_op):
      %1 = test_produce_self_handle_or_forward_operand : () -> !transform.any_op
      yield %1 : !transform.any_op
    }
    // expected-remark @below {{succeeded}}
    transform.test_consume_operand_of_op_kind_or_fail %0, "transform.test_produce_self_handle_or_forward_operand" : !transform.any_op
    transform.yield
  }
}

// -----

// expected-remark @below {{parent function}}
func.func @foo() {
  %0 = arith.constant 0 : i32
  return
}

// expected-remark @below {{parent function}}
func.func @bar() {
  %0 = arith.constant 0 : i32
  %1 = arith.constant 1 : i32
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @const : benefit(1) {
        %r = pdl.types
        %0 = pdl.operation "arith.constant" -> (%r : !pdl.range<type>)
        pdl.rewrite %0 with "transform.dialect"
      }

      transform.sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb1(%arg1: !transform.any_op):
        %f = pdl_match @const in %arg1 : (!transform.any_op) -> !transform.any_op
        %m = get_parent_op %f {isolated_from_above} : (!transform.any_op) -> !transform.any_op
        transform.debug.emit_remark_at %m, "parent function" : !transform.any_op
      }
    }
    transform.yield
  }
}

// -----

func.func @test_get_nth_parent() {
  "test.foo"() ({
    // expected-remark @below{{2nd parent}}
    "test.foo"() ({
      "test.qux"() ({
        // expected-remark @below{{1st parent}}
        "test.foo"() ({
          "test.bar"() : () -> ()
        }) : () -> ()
      }) : () -> ()
    }) : () -> ()
  }) : () -> ()
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    %f = transform.structured.match ops{["test.bar"]} in %arg0 : (!transform.any_op) -> !transform.any_op
    %parent = transform.get_parent_op %f {nth_parent = 1, op_name = "test.foo"} : (!transform.any_op) -> !transform.any_op
    transform.debug.emit_remark_at %parent, "1st parent" : !transform.any_op
    %parent2 = transform.get_parent_op %f {nth_parent = 2, op_name = "test.foo"} : (!transform.any_op) -> !transform.any_op
    transform.debug.emit_remark_at %parent2, "2nd parent" : !transform.any_op
    transform.yield
  }
}

// -----

func.func @foo() {
  %0 = arith.constant 0 : i32
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @match_func : benefit(1) {
        %0 = pdl.operands
        %1 = pdl.types
        %2 = pdl.operation "func.func"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
        pdl.rewrite %2 with "transform.dialect"
      }

      transform.sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb1(%arg1: !transform.any_op):
        // This is necessary to run the transformation on something other than the
        // top-level module, "alternatives" cannot be run on that.
        %0 = pdl_match @match_func in %arg1 : (!transform.any_op) -> !transform.any_op
        transform.alternatives %0 : !transform.any_op {
        ^bb2(%arg2: !transform.any_op):
          %1 = transform.test_produce_self_handle_or_forward_operand : () -> !transform.any_op
          // This operation fails, which triggers the next alternative without
          // reporting the error.
          transform.test_consume_operand_of_op_kind_or_fail %1, "transform.sequence" : !transform.any_op
        }, {
        ^bb2(%arg2: !transform.any_op):
          %1 = transform.test_produce_self_handle_or_forward_operand : () -> !transform.any_op
          // expected-remark @below {{succeeded}}
          transform.test_consume_operand_of_op_kind_or_fail %1, "transform.test_produce_self_handle_or_forward_operand" : !transform.any_op
        }
      }
    }
    transform.yield
  }
}

// -----

func.func private @bar()

func.func @foo() {
  call @bar() : () -> ()
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @match_call : benefit(1) {
        %0 = pdl.operands
        %1 = pdl.types
        %2 = pdl.operation "func.call"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
        pdl.rewrite %2 with "transform.dialect"
      }

      transform.sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb1(%arg1: !transform.any_op):
        %0 = pdl_match @match_call in %arg1 : (!transform.any_op) -> !transform.any_op
        %1 = get_parent_op %0 {isolated_from_above} : (!transform.any_op) -> !transform.any_op
        // expected-error @below {{all alternatives failed}}
        transform.alternatives %1 : !transform.any_op {
        ^bb2(%arg2: !transform.any_op):
          %2 = transform.pdl_match @match_call in %arg2 : (!transform.any_op) -> !transform.any_op
          // expected-remark @below {{applying}}
          transform.test_emit_remark_and_erase_operand %2, "applying" {fail_after_erase} : !transform.any_op
        }
      }
    }
    transform.yield
  }
}

// -----

func.func private @bar()

func.func @foo() {
  // expected-remark @below {{still here}}
  call @bar() : () -> ()
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @match_call : benefit(1) {
        %0 = pdl.operands
        %1 = pdl.types
        %2 = pdl.operation "func.call"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
        pdl.rewrite %2 with "transform.dialect"
      }

      transform.sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb1(%arg1: !transform.any_op):
        %0 = pdl_match @match_call in %arg1 : (!transform.any_op) -> !transform.any_op
        %1 = get_parent_op %0 {isolated_from_above} : (!transform.any_op) -> !transform.any_op
        transform.alternatives %1 : !transform.any_op {
        ^bb2(%arg2: !transform.any_op):
          %2 = transform.pdl_match @match_call in %arg2 : (!transform.any_op) -> !transform.any_op
          // expected-remark @below {{applying}}
          transform.test_emit_remark_and_erase_operand %2, "applying" {fail_after_erase} : !transform.any_op
        }, {
        ^bb2(%arg2: !transform.any_op):
          %2 = transform.pdl_match @match_call in %arg2 : (!transform.any_op) -> !transform.any_op
          transform.debug.emit_remark_at %2, "still here" : !transform.any_op
          // This alternative succeeds.
        }, {
        ^bb2(%arg2: !transform.any_op):
          // This alternative is never run, so we must not have a remark here.
          %2 = transform.pdl_match @match_call in %arg2 : (!transform.any_op) -> !transform.any_op
          transform.test_emit_remark_and_erase_operand %2, "should not happen" {fail_after_erase} : !transform.any_op
        }
      }
    }
    transform.yield
  }
}

// -----

func.func private @bar()

func.func @erase_call() {
  call @bar() : () -> ()
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @match_call : benefit(1) {
        %0 = pdl.operands
        %1 = pdl.types
        %2 = pdl.operation "func.call"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
        pdl.rewrite %2 with "transform.dialect"
      }

      transform.sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb1(%arg1: !transform.any_op):
        %0 = pdl_match @match_call in %arg1 : (!transform.any_op) -> !transform.any_op
        %1 = get_parent_op %0 {isolated_from_above} : (!transform.any_op) -> !transform.any_op
        transform.alternatives %1 : !transform.any_op {
        ^bb2(%arg2: !transform.any_op):
          %2 = transform.pdl_match @match_call in %arg2 : (!transform.any_op) -> !transform.any_op
          // expected-remark @below {{applying}}
          transform.test_emit_remark_and_erase_operand %2, "applying" {fail_after_erase} : !transform.any_op
        }, {
        ^bb2(%arg2: !transform.any_op):
          %2 = transform.pdl_match @match_call in %arg2 : (!transform.any_op) -> !transform.any_op
          // expected-remark @below {{applying second time}}
          transform.test_emit_remark_and_erase_operand %2, "applying second time" : !transform.any_op
        }
      }
    }
    transform.yield
  }
}

// -----

func.func private @bar()

func.func @foo() {
  call @bar() : () -> ()
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @match_call : benefit(1) {
        %0 = pdl.operands
        %1 = pdl.types
        %2 = pdl.operation "func.call"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
        pdl.rewrite %2 with "transform.dialect"
      }

      transform.sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb1(%arg1: !transform.any_op):
        %0 = pdl_match @match_call in %arg1 : (!transform.any_op) -> !transform.any_op
        %1 = get_parent_op %0 {isolated_from_above} : (!transform.any_op) -> !transform.any_op
        %2 = transform.alternatives %1 : !transform.any_op -> !transform.any_op {
        ^bb2(%arg2: !transform.any_op):
          %3 = transform.pdl_match @match_call in %arg2 : (!transform.any_op) -> !transform.any_op
          // expected-remark @below {{applying}}
          transform.test_emit_remark_and_erase_operand %3, "applying" {fail_after_erase} : !transform.any_op
          %4 = transform.test_produce_self_handle_or_forward_operand %3 : (!transform.any_op) -> !transform.any_op
          transform.yield %4 : !transform.any_op
        }, {
        ^bb2(%arg2: !transform.any_op):
          %4 = transform.test_produce_self_handle_or_forward_operand : () -> !transform.any_op
          transform.yield %4 : !transform.any_op
        }
        // The first alternative failed, so the returned value is taken from the
        // second alternative, associated test_produce_self_handle_or_forward_operand rather
        // than pdl_match.
        // expected-remark @below {{succeeded}}
        transform.test_consume_operand_of_op_kind_or_fail %2, "transform.test_produce_self_handle_or_forward_operand" : !transform.any_op
      }
    }
    transform.yield
  }
}

// -----

// expected-note @below {{scope}}
module attributes {transform.with_named_sequence} {
  func.func @foo() {
    %0 = arith.constant 0 : i32
    return
  }

  func.func @bar() {
    %0 = arith.constant 0 : i32
    %1 = arith.constant 1 : i32
    return
  }

  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
    // expected-error @below {{scope must not contain the transforms being applied}}
    transform.alternatives %arg1 : !transform.any_op {
    ^bb2(%arg2: !transform.any_op):
      %0 = transform.test_produce_self_handle_or_forward_operand : () -> !transform.any_op
      transform.test_consume_operand_of_op_kind_or_fail %0, "transform.sequence" : !transform.any_op
    }, {
    ^bb2(%arg2: !transform.any_op):
      %0 = transform.test_produce_self_handle_or_forward_operand : () -> !transform.any_op
      transform.test_consume_operand_of_op_kind_or_fail %0, "transform.test_produce_self_handle_or_forward_operand" : !transform.any_op
    }
    transform.yield
  }
}

// -----

func.func @foo(%arg0: index, %arg1: index, %arg2: index) {
  // expected-note @below {{scope}}
  scf.for %i = %arg0 to %arg1 step %arg2 {
    %0 = arith.constant 0 : i32
  }
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @match_const : benefit(1) {
        %0 = pdl.operands
        %1 = pdl.types
        %2 = pdl.operation "arith.constant"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
        pdl.rewrite %2 with "transform.dialect"
      }


      sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb1(%arg1: !transform.any_op):
        %0 = transform.pdl_match @match_const in %arg1 : (!transform.any_op) -> !transform.any_op
        %1 = transform.get_parent_op %0 {op_name = "scf.for"} : (!transform.any_op) -> !transform.any_op
        // expected-error @below {{only isolated-from-above ops can be alternative scopes}}
        alternatives %1 : !transform.any_op {
        ^bb2(%arg2: !transform.any_op):
        }
      }
    }
    transform.yield
  }
}
// -----

func.func @foo() {
  // expected-note @below {{when applied to this op}}
  "op" () : () -> ()
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @some : benefit(1) {
        %0 = pdl.operands
        %1 = pdl.types
        %2 = pdl.operation "op"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
        pdl.rewrite %2 with "transform.dialect"
      }

      transform.sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb0(%arg1: !transform.any_op):
        %0 = pdl_match @some in %arg1 : (!transform.any_op) -> !transform.any_op
        // expected-error @below {{application of transform.test_wrong_number_of_results expected to produce 3 results (actually produced 1).}}
        // expected-note @below {{if you need variadic results, consider a generic `apply` instead of the specialized `applyToOne`.}}
        transform.test_wrong_number_of_results %0 : (!transform.any_op) -> (!transform.any_op, !transform.any_op, !transform.any_op)
      }
    }
    transform.yield
  }
}

// -----

func.func @foo() {
  "op" () : () -> ()
  // expected-note @below {{when applied to this op}}
  "op" () : () -> ()
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @some : benefit(1) {
        %0 = pdl.operands
        %1 = pdl.types
        %2 = pdl.operation "op"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
        pdl.rewrite %2 with "transform.dialect"
      }

      transform.sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb0(%arg1: !transform.any_op):
        %0 = pdl_match @some in %arg1 : (!transform.any_op) -> !transform.any_op
        // expected-error @below {{application of transform.test_wrong_number_of_multi_results expected to produce 1 results (actually produced 0)}}
        // expected-note @below {{if you need variadic results, consider a generic `apply` instead of the specialized `applyToOne`.}}
        transform.test_wrong_number_of_multi_results %0 : (!transform.any_op) -> (!transform.any_op)
      }
    }
    transform.yield
  }
}

// -----

func.func @foo() {
  "op" () : () -> ()
  "op" () : () -> ()
  "op" () : () -> ()
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @some : benefit(1) {
        %0 = pdl.operands
        %1 = pdl.types
        %2 = pdl.operation "op"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
        pdl.rewrite %2 with "transform.dialect"
      }

      transform.sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb0(%arg1: !transform.any_op):
        %0 = pdl_match @some in %arg1 : (!transform.any_op) -> !transform.any_op
        // Transform matches 3 ops and produces 2 results.
        %1:2 = transform.test_correct_number_of_multi_results %0 : (!transform.any_op) -> (!transform.any_op, !transform.any_op)
      }
    }
    transform.yield
  }
}

// -----

func.func @foo() {
  "wrong_op_name" () : () -> ()
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @some : benefit(1) {
        %0 = pdl.operands
        %1 = pdl.types
        %2 = pdl.operation "op"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
        pdl.rewrite %2 with "transform.dialect"
      }

      transform.sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb0(%arg1: !transform.any_op):
        %0 = pdl_match @some in %arg1 : (!transform.any_op) -> !transform.any_op
        // Transform fails to match any but still produces 2 results.
        %1:2 = transform.test_correct_number_of_multi_results %0 : (!transform.any_op) -> (!transform.any_op, !transform.any_op)
      }
    }
    transform.yield
  }
}

// -----

// This should not fail.

func.func @foo() {
  "op" () : () -> ()
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @some : benefit(1) {
        %0 = pdl.operands
        %1 = pdl.types
        %2 = pdl.operation "op"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
        pdl.rewrite %2 with "transform.dialect"
      }

      transform.sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb0(%arg1: !transform.any_op):
        %0 = pdl_match @some in %arg1 : (!transform.any_op) -> !transform.any_op
        transform.test_mixed_null_and_non_null_results %0 : (!transform.any_op) -> (!transform.any_op, !transform.any_op)
      }
    }
    transform.yield
  }
}

// -----

// Expecting to match all operations by merging the handles that matched addi
// and subi separately.
func.func @foo(%arg0: index) {
  // expected-remark @below {{matched}}
  %0 = arith.addi %arg0, %arg0 : index
  // expected-remark @below {{matched}}
  %1 = arith.subi %arg0, %arg0 : index
  // expected-remark @below {{matched}}
  %2 = arith.addi %0, %1 : index
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @addi : benefit(1) {
        %0 = pdl.operands
        %1 = pdl.types
        %2 = pdl.operation "arith.addi"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
        pdl.rewrite %2 with "transform.dialect"
      }
      pdl.pattern @subi : benefit(1) {
        %0 = pdl.operands
        %1 = pdl.types
        %2 = pdl.operation "arith.subi"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
        pdl.rewrite %2 with "transform.dialect"
      }

      transform.sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb0(%arg1: !transform.any_op):
        %0 = pdl_match @addi in %arg1 : (!transform.any_op) -> !transform.any_op
        %1 = pdl_match @subi in %arg1 : (!transform.any_op) -> !transform.any_op
        %2 = merge_handles %0, %1 : !transform.any_op
        transform.debug.emit_remark_at %2, "matched" : !transform.any_op
      }
    }
    transform.yield
  }
}

// -----

func.func @foo(%arg0: index) {
  %0 = arith.addi %arg0, %arg0 : index
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @addi : benefit(1) {
        %0 = pdl.operands
        %1 = pdl.types
        %2 = pdl.operation "arith.addi"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
        pdl.rewrite %2 with "transform.dialect"
      }

      transform.sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb0(%arg1: !transform.any_op):
        %0 = pdl_match @addi in %arg1 : (!transform.any_op) -> !transform.any_op
        %1 = pdl_match @addi in %arg1 : (!transform.any_op) -> !transform.any_op
        %2 = merge_handles deduplicate %0, %1 : !transform.any_op
        %3 = num_associations %2 : (!transform.any_op) -> !transform.param<i64>
        // expected-remark @below {{1}}
        transform.debug.emit_param_as_remark  %3 : !transform.param<i64>
      }
    }
    transform.yield
  }
}

// -----

func.func @foo() {
  "op" () { target_me } : () -> ()
  // expected-note @below {{when applied to this op}}
  "op" () : () -> ()
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @some : benefit(1) {
        %0 = pdl.operands
        %1 = pdl.types
        %2 = pdl.operation "op"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
        pdl.rewrite %2 with "transform.dialect"
      }

      transform.sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb0(%arg1: !transform.any_op):
        %0 = pdl_match @some in %arg1 : (!transform.any_op) -> !transform.any_op
        // expected-error @below {{failed to apply}}
        transform.test_mixed_success_and_silenceable %0 : !transform.any_op
      }
    }
    transform.yield
  }
}

// -----

func.func @foo() {
  "op" () : () -> ()
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @some : benefit(1) {
        %0 = pdl.operands
        %1 = pdl.types
        %2 = pdl.operation "op"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
        pdl.rewrite %2 with "transform.dialect"
      }

      transform.sequence %arg0 : !transform.any_op failures(suppress) {
      ^bb0(%arg1: !transform.any_op):
        %0 = pdl_match @some in %arg1 : (!transform.any_op) -> !transform.any_op
        // Not expecting error here because we are suppressing it.
        // expected-remark @below {{foo}}
        test_emit_remark_and_erase_operand %0, "foo" {fail_after_erase} : !transform.any_op
      }
    }
    transform.yield
  }
}

// -----

func.func @foo() {
  "op" () : () -> ()
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @some : benefit(1) {
        %0 = pdl.operands
        %1 = pdl.types
        %2 = pdl.operation "op"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
        pdl.rewrite %2 with "transform.dialect"
      }

      transform.sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb0(%arg1: !transform.any_op):
        %0 = pdl_match @some in %arg1 : (!transform.any_op) -> !transform.any_op
        // expected-error @below {{silenceable error}}
        // expected-remark @below {{foo}}
        test_emit_remark_and_erase_operand %0, "foo" {fail_after_erase} : !transform.any_op
      }
    }
    transform.yield
  }
}


// -----

module attributes {transform.with_named_sequence} {
  func.func private @foo()
  func.func private @bar()

  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {

    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @func : benefit(1) {
        %0 = pdl.operands
        %1 = pdl.types
        %2 = pdl.operation "func.func"(%0 : !pdl.range<value>) -> (%1 : !pdl.range<type>)
        pdl.rewrite %2 with "transform.dialect"
      }

      transform.sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb0(%arg1: !transform.any_op):
        %0 = pdl_match @func in %arg1 : (!transform.any_op) -> !transform.any_op
        %1 = replicate num(%0) %arg1 : !transform.any_op, !transform.any_op
        %p = num_associations %1 : (!transform.any_op) -> !transform.param<i64>
        // expected-remark @below {{2}}
        transform.debug.emit_param_as_remark  %p : !transform.param<i64>
        %2 = replicate num(%0) %1 : !transform.any_op, !transform.any_op
        %p2 = num_associations %2 : (!transform.any_op) -> !transform.param<i64>
        // expected-remark @below {{4}}
        transform.debug.emit_param_as_remark  %p2 : !transform.param<i64>
      }
    }
    transform.yield
  }
}

// -----

func.func @bar() {
  // expected-remark @below {{transform applied}}
  %0 = arith.constant 0 : i32
  // expected-remark @below {{transform applied}}
  %1 = arith.constant 1 : i32
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @const : benefit(1) {
        %r = pdl.types
        %0 = pdl.operation "arith.constant" -> (%r : !pdl.range<type>)
        pdl.rewrite %0 with "transform.dialect"
      }

      transform.sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb1(%arg1: !transform.any_op):
        %f = pdl_match @const in %arg1 : (!transform.any_op) -> !transform.any_op
        transform.foreach %f : !transform.any_op {
        ^bb2(%arg2: !transform.any_op):
          %p = transform.num_associations %arg2 : (!transform.any_op) -> !transform.param<i64>
          // expected-remark @below {{1}}
          transform.debug.emit_param_as_remark  %p : !transform.param<i64>
          transform.debug.emit_remark_at %arg2, "transform applied" : !transform.any_op
        }
      }
    }
    transform.yield
  }
}

// -----

// CHECK-LABEL: func @consume_in_foreach()
//  CHECK-NEXT:   return
func.func @consume_in_foreach() {
  %0 = arith.constant 0 : index
  %1 = arith.constant 1 : index
  %2 = arith.constant 2 : index
  %3 = arith.constant 3 : index
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
    %f = transform.structured.match ops{["arith.constant"]} in %arg1 : (!transform.any_op) -> !transform.any_op
    transform.foreach %f : !transform.any_op {
    ^bb2(%arg2: !transform.any_op):
      // expected-remark @below {{erasing}}
      transform.test_emit_remark_and_erase_operand %arg2, "erasing" : !transform.any_op
    }
    transform.yield
  }
}

// -----

func.func @bar() {
  scf.execute_region {
    // expected-remark @below {{transform applied}}
    %0 = arith.constant 0 : i32
    scf.yield
  }

  scf.execute_region {
    // expected-remark @below {{transform applied}}
    %1 = arith.constant 1 : i32
    // expected-remark @below {{transform applied}}
    %2 = arith.constant 2 : i32
    scf.yield
  }

  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @const : benefit(1) {
        %r = pdl.types
        %0 = pdl.operation "arith.constant" -> (%r : !pdl.range<type>)
        pdl.rewrite %0 with "transform.dialect"
      }

      pdl.pattern @execute_region : benefit(1) {
        %r = pdl.types
        %0 = pdl.operation "scf.execute_region" -> (%r : !pdl.range<type>)
        pdl.rewrite %0 with "transform.dialect"
      }

      transform.sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb1(%arg1: !transform.any_op):
        %f = pdl_match @execute_region in %arg1 : (!transform.any_op) -> !transform.any_op
        %results = transform.foreach %f : !transform.any_op -> !transform.any_op {
        ^bb2(%arg2: !transform.any_op):
          %g = transform.pdl_match @const in %arg2 : (!transform.any_op) -> !transform.any_op
          transform.yield %g : !transform.any_op
        }

        %p = transform.num_associations %results : (!transform.any_op) -> !transform.param<i64>
        // expected-remark @below {{3}}
        transform.debug.emit_param_as_remark  %p : !transform.param<i64>
        transform.debug.emit_remark_at %results, "transform applied" : !transform.any_op
      }
    }
    transform.yield
  }
}

// -----

func.func @get_parent_for_op_no_loop(%arg0: index, %arg1: index) {
  // expected-remark @below {{found muli}}
  %0 = arith.muli %arg0, %arg1 : index
  arith.addi %0, %arg1 : index
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
    %addi = transform.structured.match ops{["arith.addi"]} in %arg1 : (!transform.any_op) -> !transform.any_op
    %muli = transform.get_producer_of_operand %addi[0] : (!transform.any_op) -> !transform.any_op
    transform.debug.emit_remark_at %muli, "found muli" : !transform.any_op
    transform.yield
  }
}

// -----

func.func @get_parent_for_op_no_loop(%arg0: index, %arg1: index) {
  // expected-note @below {{target op}}
  %0 = arith.muli %arg0, %arg1 : index
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
    %muli = transform.structured.match ops{["arith.muli"]} in %arg1 : (!transform.any_op) -> !transform.any_op
    // expected-error @below {{could not find a producer for operand number: 0 of}}
    %bbarg = transform.get_producer_of_operand %muli[0] : (!transform.any_op) -> !transform.any_op
    transform.yield
  }
}

// -----

func.func @get_consumer(%arg0: index, %arg1: index) {
  %0 = arith.muli %arg0, %arg1 : index
  // expected-remark @below {{found addi}}
  arith.addi %0, %arg1 : index
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
    %muli = transform.structured.match ops{["arith.muli"]} in %arg1 : (!transform.any_op) -> !transform.any_op
    %addi = transform.get_consumers_of_result %muli[0] : (!transform.any_op) -> !transform.any_op
    transform.debug.emit_remark_at %addi, "found addi" : !transform.any_op
    transform.yield
  }
}

// -----

func.func @get_consumer_fail_1(%arg0: index, %arg1: index) {
  %0 = arith.muli %arg0, %arg1 : index
  %1 = arith.muli %arg0, %arg1 : index
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
    %muli = transform.structured.match ops{["arith.muli"]} in %arg1 : (!transform.any_op) -> !transform.any_op
    // expected-error @below {{handle must be mapped to exactly one payload op}}
    %bbarg = transform.get_consumers_of_result %muli[0] : (!transform.any_op) -> !transform.any_op
    transform.yield
  }
}

// -----

func.func @get_consumer_fail_2(%arg0: index, %arg1: index) {
  %0 = arith.muli %arg0, %arg1 : index
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
    %muli = transform.structured.match ops{["arith.muli"]} in %arg1 : (!transform.any_op) -> !transform.any_op
    // expected-error @below {{result number overflow}}
    %bbarg = transform.get_consumers_of_result %muli[1] : (!transform.any_op) -> !transform.any_op
    transform.yield
  }
}

// -----

func.func @split_handle(%a: index, %b: index, %c: index) {
  %0 = arith.muli %a, %b : index
  %1 = arith.muli %a, %c : index
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%fun: !transform.any_op) {
    %muli = transform.structured.match ops{["arith.muli"]} in %fun : (!transform.any_op) -> !transform.any_op
    %h:2 = transform.split_handle %muli : (!transform.any_op) -> (!transform.any_op, !transform.any_op)
    %p = transform.num_associations %h#0 : (!transform.any_op) -> !transform.param<i64>
    // expected-remark @below {{1}}
    transform.debug.emit_param_as_remark  %p : !transform.param<i64>
    %muli_2 = transform.structured.match ops{["arith.muli"]} in %fun : (!transform.any_op) -> !transform.any_op
    // expected-error @below {{expected to contain 3 payload ops but it contains 2 payload ops}}
    %h_2:3 = transform.split_handle %muli_2 : (!transform.any_op) -> (!transform.any_op, !transform.any_op, !transform.any_op)
    transform.yield
  }
}

// -----

func.func @split_handle(%a: index, %b: index, %c: index) {
  %0 = arith.muli %a, %b : index
  %1 = arith.muli %a, %c : index
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.sequence %root : !transform.any_op failures(suppress) {
    ^bb1(%fun: !transform.any_op):
      %muli = transform.structured.match ops{["arith.muli"]} in %fun : (!transform.any_op) -> !transform.any_op
      %h:2 = split_handle %muli : (!transform.any_op) -> (!transform.any_op, !transform.any_op)
      %p = transform.num_associations %h#0 : (!transform.any_op) -> !transform.param<i64>
      // expected-remark @below {{1}}
      transform.debug.emit_param_as_remark  %p : !transform.param<i64>
      %muli_2 = transform.structured.match ops{["arith.muli"]} in %fun : (!transform.any_op) -> !transform.any_op
      // Silenceable failure and all handles are now empty.
      %h_2:3 = split_handle %muli_2 : (!transform.any_op) -> (!transform.any_op, !transform.any_op, !transform.any_op)
      %p2 = transform.num_associations %h_2#0 : (!transform.any_op) -> !transform.param<i64>
      // expected-remark @below {{0}}
      transform.debug.emit_param_as_remark  %p2 : !transform.param<i64>
    }
    transform.yield
  }
}

// -----

func.func @split_handle(%a: index, %b: index, %c: index) {
  %0 = arith.muli %a, %b : index
  %1 = arith.muli %a, %c : index
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%fun: !transform.any_op) {
    %muli_2 = transform.structured.match ops{["arith.muli"]} in %fun : (!transform.any_op) -> !transform.any_op
    // No error, last result handle is empty.
    %h:3 = transform.split_handle %muli_2 {fail_on_payload_too_small = false} : (!transform.any_op) -> (!transform.any_op, !transform.any_op, !transform.any_op)
    %p = transform.num_associations %h#0 : (!transform.any_op) -> !transform.param<i64>
    // expected-remark @below {{1}}
    transform.debug.emit_param_as_remark  %p : !transform.param<i64>
    %p2 = transform.num_associations %h#1 : (!transform.any_op) -> !transform.param<i64>
    // expected-remark @below {{1}}
    transform.debug.emit_param_as_remark  %p2 : !transform.param<i64>
    %p3 = transform.num_associations %h#2 : (!transform.any_op) -> !transform.param<i64>
    // expected-remark @below {{0}}
    transform.debug.emit_param_as_remark  %p3 : !transform.param<i64>
    transform.yield
  }
}

// -----

func.func @split_handle(%a: index, %b: index, %c: index) {
  %0 = arith.muli %a, %b : index
  %1 = arith.muli %a, %c : index
  %2 = arith.muli %a, %c : index
  %3 = arith.muli %a, %c : index
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%fun: !transform.any_op) {
    %muli_2 = transform.structured.match ops{["arith.muli"]} in %fun : (!transform.any_op) -> !transform.any_op
    %h:2 = transform.split_handle %muli_2 {overflow_result = 0} : (!transform.any_op) -> (!transform.any_op, !transform.any_op)
    %p = transform.num_associations %h#0 : (!transform.any_op) -> !transform.param<i64>
    // expected-remark @below {{3}}
    transform.debug.emit_param_as_remark  %p : !transform.param<i64>
    %p2 = transform.num_associations %h#1 : (!transform.any_op) -> !transform.param<i64>
    // expected-remark @below {{1}}
    transform.debug.emit_param_as_remark  %p2 : !transform.param<i64>
    transform.yield
  }
}

// -----

"test.some_op"() : () -> ()
"other_dialect.other_op"() : () -> ()

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @some : benefit(1) {
        %0 = pdl.operation "test.some_op"
        pdl.rewrite %0 with "transform.dialect"
      }

      sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb1(%arg1: !transform.any_op):
        %0 = pdl_match @some in %arg1 : (!transform.any_op) -> !transform.any_op
        %2 = transform.cast %0 : !transform.any_op to !transform.test_dialect_op
        transform.cast %2 : !transform.test_dialect_op to !transform.any_op
      }
    }
    transform.yield
  }
}

// -----

"test.some_op"() : () -> ()
"other_dialect.other_op"() : () -> ()

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @other : benefit(1) {
        %0 = pdl.operation "other_dialect.other_op"
        pdl.rewrite %0 with "transform.dialect"
      }

      sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb1(%arg1: !transform.any_op):
        %0 = pdl_match @other in %arg1 : (!transform.any_op) -> !transform.any_op
        // expected-error @below {{expected the payload operation to belong to the 'test' dialect}}
        %2 = transform.cast %0 : !transform.any_op to !transform.test_dialect_op
        transform.cast %2 : !transform.test_dialect_op to !transform.any_op
      }
    }
    transform.yield
  }
}

// -----

"test.some_op"() : () -> ()
"other_dialect.other_op"() : () -> ()

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @some : benefit(1) {
        %0 = pdl.operation "test.some_op"
        pdl.rewrite %0 with "transform.dialect"
      }

      sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb1(%arg1: !transform.any_op):
        %0 = pdl_match @some in %arg1 : (!transform.any_op) -> !transform.any_op
        %2 = transform.cast %0 : !transform.any_op to !transform.op<"test.some_op">
        transform.cast %2 : !transform.op<"test.some_op"> to !transform.any_op
      }
    }
    transform.yield
  }
}

// -----

"test.some_op"() : () -> ()
// expected-note @below {{payload operation}}
"other_dialect.other_op"() : () -> ()

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @other : benefit(1) {
        %0 = pdl.operation "other_dialect.other_op"
        pdl.rewrite %0 with "transform.dialect"
      }

      sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb1(%arg1: !transform.any_op):
        %0 = pdl_match @other in %arg1 : (!transform.any_op) -> !transform.any_op
        // expected-error @below {{incompatible payload operation name}}
        %2 = transform.cast %0 : !transform.any_op to !transform.op<"test.some_op">
        transform.cast %2 : !transform.op<"test.some_op"> to !transform.any_op
      }
    }
    transform.yield
  }
}

// -----

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      transform.sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb0(%arg1: !transform.any_op):
        %0 = pdl_match @some in %arg1 : (!transform.any_op) -> !transform.any_op
        // here, the handles nested under are {%root, %arg0, %arg1, %0}
        // expected-remark @below {{4 handles nested under}}
        transform.test_report_number_of_tracked_handles_nested_under %arg1 : !transform.any_op
        // expected-remark @below {{erased}}
        transform.test_emit_remark_and_erase_operand %0, "erased" : !transform.any_op
        // here, the handles nested under are only {%root, %arg0, %arg1}
        // expected-remark @below {{3 handles nested under}}
        transform.test_report_number_of_tracked_handles_nested_under %arg1 : !transform.any_op
      }

      pdl.pattern @some : benefit(1) {
        %0 = pdl.operation "test.some_op"
        pdl.rewrite %0 with "transform.dialect"
      }
    }
    transform.yield
  }
}

"test.some_op"() : () -> ()

// -----

func.func @split_handle(%a: index, %b: index, %c: index) {
  %0 = arith.muli %a, %b : index
  %1 = arith.muli %a, %c : index
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.sequence %root : !transform.any_op -> !transform.any_op failures(propagate) {
    ^bb1(%fun: !transform.any_op):
      %muli = transform.structured.match ops{["arith.muli"]} in %fun : (!transform.any_op) -> !transform.any_op
      // expected-error @below {{expected to contain 3 payload ops but it contains 2 payload ops}}
      %h_2:3 = split_handle %muli : (!transform.any_op) -> (!transform.any_op, !transform.any_op, !transform.any_op)
      /// Test that yield does not crash in the presence of silenceable error in
      /// propagate mode.
      yield %fun : !transform.any_op
    }
    transform.yield
  }
}

// -----

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.sequence %root : !transform.any_op -> !transform.any_op failures(suppress) {
    ^bb0(%arg0: !transform.any_op):
      %muli = transform.structured.match ops{["arith.muli"]} in %arg0 : (!transform.any_op) -> !transform.any_op
      // Edge case propagating empty handles in splitting.
      %0:3 = split_handle %muli : (!transform.any_op) -> (!transform.any_op, !transform.any_op, !transform.any_op)
      // Test does not crash when accessing the empty handle.
      yield %0#0 : !transform.any_op
    }
    transform.yield
  }
}

// -----

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    %0 = transform.test_produce_param (0 : i32) : !transform.test_dialect_param
    // expected-remark @below {{0 : i32}}
    transform.debug.emit_param_as_remark  %0 : !transform.test_dialect_param
    transform.yield
  }
}

// -----

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    // expected-error @below {{expected the type of the parameter attribute ('i32') to match the parameter type ('i64')}}
    transform.test_produce_param (0 : i32) : !transform.param<i64>
    transform.yield
  }
}

// -----


module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    %0 = transform.test_add_to_param 40
    %1 = transform.test_add_to_param %0, 2
    // expected-remark @below {{42 : i32}}
    transform.debug.emit_param_as_remark  %1 : !transform.test_dialect_param
    transform.yield
  }
}

// -----

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    %0 = transform.structured.match ops{["func.func"]} in %arg0 : (!transform.any_op) -> !transform.any_op
    %1 = transform.test_produce_param_with_number_of_test_ops %0 : !transform.any_op
    // expected-remark @below {{1 : i32, 3 : i32}}
    transform.debug.emit_param_as_remark  %1 : !transform.test_dialect_param
    %2 = transform.test_add_to_param %1, 100
    // expected-remark @below {{101 : i32, 103 : i32}}
    transform.debug.emit_param_as_remark  %2 : !transform.test_dialect_param
    transform.yield
  }
}

func.func private @one_test_op(%arg0: i32) {
  "test.op_a"(%arg0) { attr = 0 : i32} : (i32) -> i32
  return
}

func.func private @three_test_ops(%arg0: i32) {
  "test.op_a"(%arg0) { attr = 0 : i32} : (i32) -> i32
  "test.op_a"(%arg0) { attr = 0 : i32} : (i32) -> i32
  "test.op_a"(%arg0) { attr = 0 : i32} : (i32) -> i32
  return
}

// -----

// expected-note @below {{when applied to this op}}
module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    // expected-error @below {{expected to produce an Operation * for result #0}}
    transform.test_produce_transform_param_or_forward_operand %arg0
      { first_result_is_param }
      : (!transform.any_op) -> (!transform.any_op, !transform.param<i64>)
    transform.yield
  }
}

// -----

// Should not fail.

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    transform.test_produce_transform_param_or_forward_operand %arg0
      { first_result_is_null }
      : (!transform.any_op) -> (!transform.any_op, !transform.param<i64>)
    transform.yield
  }
}

// -----

// expected-note @below {{when applied to this op}}
module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    // expected-error @below {{expected to produce an Attribute for result #1}}
    transform.test_produce_transform_param_or_forward_operand %arg0
      { second_result_is_handle }
      : (!transform.any_op) -> (!transform.any_op, !transform.param<i64>)
    transform.yield
  }
}

// -----

// expected-note @below {{when applied to this op}}
module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    // expected-error @below {{expected to produce a Value for result #0}}
    transform.test_produce_transform_param_or_forward_operand %arg0
      { second_result_is_handle }
      : (!transform.any_op) -> (!transform.any_value, !transform.param<i64>)
    transform.yield
  }
}

// -----

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    // expected-error @below {{attempting to assign a null payload op to this transform value}}
    %0 = transform.test_produce_null_payload : !transform.any_op
    transform.yield
  }
}

// -----

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    // expected-error @below {{attempting to assign a null parameter to this transform value}}
    %0 = transform.test_produce_null_param : !transform.param<i64>
    transform.yield
  }
}

// -----

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    // expected-error @below {{attempting to assign a null payload value to this transform handle}}
    %0 = transform.test_produce_null_value : !transform.any_value
    transform.yield
  }
}

// -----

// expected-error @below {{could not find a nested named sequence with name: __transform_main}}
// expected-error @below {{could not find transform entry point: __transform_main in either payload or transform module}}
module {
}

// -----

module attributes {transform.with_named_sequence} {
  // expected-remark @below {{value handle}}
  // expected-note @below {{value handle points to a block argument #0 in block #0 in region #0}}
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    %0 = transform.test_produce_value_handle_to_self_operand %arg0 : (!transform.any_op) -> !transform.any_value
    transform.debug.emit_remark_at %0, "value handle" : !transform.any_value
    transform.yield
  }
}

// -----

// expected-remark @below {{result handle}}
// expected-note @below {{value handle points to an op result #1}}
%0:2 = "test.get_two_results"() : () -> (i32, i32)
// expected-remark @below {{result handle}}
// expected-note @below {{value handle points to an op result #1}}
%1:3 = "test.get_three_results"() : () -> (i32, i32, f32)

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    %2 = transform.structured.match ops{["test.get_two_results", "test.get_three_results"]} in %arg0 : (!transform.any_op) -> !transform.any_op
    %3 = transform.test_produce_value_handle_to_result %2, 1 : (!transform.any_op) -> !transform.any_value
    transform.debug.emit_remark_at %3, "result handle" : !transform.any_value
    transform.yield
  }
}

// -----

"test.op_with_regions"() ({
^bb0:
  "test.regon_terminator"() : () -> ()
}, {
^bb1:
  "test.regon_terminator"() : () -> ()
// expected-remark @below {{block argument handle}}
// expected-note @below {{value handle points to a block argument #2 in block #1 in region #1}}
^bb2(%arg0: i32, %arg1: f64, %arg3: index):
  "test.match_anchor"() : () -> ()
  "test.regon_terminator"() : () -> ()
}) : () -> ()

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    %2 = transform.structured.match ops{["test.match_anchor"]} in %arg0 : (!transform.any_op) -> !transform.any_op
    %3 = transform.test_produce_value_handle_to_argument_of_parent_block %2, 2 : (!transform.any_op) -> !transform.any_value
    transform.debug.emit_remark_at %3, "block argument handle" : !transform.any_value
    transform.yield
  }
}

// -----

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    // expected-note @below {{value defined here with type '!transform.test_dialect_param'}}
    %0 = transform.test_produce_param_with_number_of_test_ops %arg0 : !transform.any_op
    // expected-error @below {{unexpectedly consumed a value that is not a handle as operand #0}}
    transform.test_consume_operand %0 : !transform.test_dialect_param
    transform.yield
  }
}

// -----

// expected-remark @below {{addi operand}}
// expected-note @below {{value handle points to a block argument #0}}
func.func @get_operand_of_op(%arg0: index, %arg1: index) -> index {
  %r = arith.addi %arg0, %arg1 : index
  return %r : index
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
    %addi = transform.structured.match ops{["arith.addi"]} in %arg1 : (!transform.any_op) -> !transform.any_op
    %operand = transform.get_operand %addi[0] : (!transform.any_op) -> !transform.any_value
    transform.debug.emit_remark_at %operand, "addi operand" : !transform.any_value
    transform.yield
  }
}

// -----

func.func @get_out_of_bounds_operand_of_op(%arg0: index, %arg1: index) -> index {
  // expected-note @below {{while considering positions of this payload operation}}
  %r = arith.addi %arg0, %arg1 : index
  return %r : index
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
    %addi = transform.structured.match ops{["arith.addi"]} in %arg1 : (!transform.any_op) -> !transform.any_op
    // expected-error @below {{position overflow 2 (updated from 2) for maximum 2}}
    %operand = transform.get_operand %addi[2] : (!transform.any_op) -> !transform.any_value
    transform.debug.emit_remark_at %operand, "addi operand" : !transform.any_value
    transform.yield
  }
}

// -----

// expected-remark @below {{addi operand}}
// expected-note @below {{value handle points to a block argument #1}}
func.func @get_inverted_operand_of_op(%arg0: index, %arg1: index) -> index {
  %r = arith.addi %arg0, %arg1 : index
  return %r : index
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
    %addi = transform.structured.match ops{["arith.addi"]} in %arg1 : (!transform.any_op) -> !transform.any_op
    %operand = transform.get_operand %addi[except(0)] : (!transform.any_op) -> !transform.any_value
    transform.debug.emit_remark_at %operand, "addi operand" : !transform.any_value
    transform.yield
  }
}

// -----

func.func @get_multiple_operands_of_op(%arg0: index, %arg1: index) -> index {
  %r = arith.addi %arg0, %arg1 : index
  return %r : index
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
    %addui = transform.structured.match ops{["arith.addi"]} in %arg1 : (!transform.any_op) -> !transform.any_op
    %operands = transform.get_operand %addui[all] : (!transform.any_op) -> !transform.any_value
    %p = transform.num_associations %operands : (!transform.any_value) -> !transform.param<i64>
    // expected-remark @below {{2}}
    transform.debug.emit_param_as_remark %p : !transform.param<i64>
    transform.yield
  }
}

// -----

func.func @get_result_of_op(%arg0: index, %arg1: index) -> index {
  // expected-remark @below {{addi result}}
  // expected-note @below {{value handle points to an op result #0}}
  %r = arith.addi %arg0, %arg1 : index
  return %r : index
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
    %addi = transform.structured.match ops{["arith.addi"]} in %arg1 : (!transform.any_op) -> !transform.any_op
    %result = transform.get_result %addi[0] : (!transform.any_op) -> !transform.any_value
    transform.debug.emit_remark_at %result, "addi result" : !transform.any_value
    transform.yield
  }
}

// -----

func.func @get_out_of_bounds_result_of_op(%arg0: index, %arg1: index) -> index {
  // expected-note @below {{while considering positions of this payload operation}}
  %r = arith.addi %arg0, %arg1 : index
  return %r : index
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
    %addi = transform.structured.match ops{["arith.addi"]} in %arg1 : (!transform.any_op) -> !transform.any_op
    // expected-error @below {{position overflow 1 (updated from 1) for maximum 1}}
    %result = transform.get_result %addi[1] : (!transform.any_op) -> !transform.any_value
    transform.debug.emit_remark_at %result, "addi result" : !transform.any_value
    transform.yield
  }
}

// -----

func.func @get_result_of_op(%arg0: index, %arg1: index) -> index {
  // expected-remark @below {{matched}}
  %r = arith.addi %arg0, %arg1 : index
  return %r : index
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
    %addi = transform.structured.match ops{["arith.addi"]} in %arg1 : (!transform.any_op) -> !transform.any_op
    %result = transform.get_result %addi[0] : (!transform.any_op) -> !transform.any_value
    %op = transform.get_defining_op %result : (!transform.any_value) -> !transform.any_op
    transform.debug.emit_remark_at %op, "matched" : !transform.any_op
    transform.yield
  }
}

// -----

func.func @get_multiple_result_of_op(%arg0: index, %arg1: index) -> (index, i1) {
  %r, %b = arith.addui_extended %arg0, %arg1 : index, i1
  return %r, %b : index, i1
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
    %addui = transform.structured.match ops{["arith.addui_extended"]} in %arg1 : (!transform.any_op) -> !transform.any_op
    %results = transform.get_result %addui[all] : (!transform.any_op) -> !transform.any_value
    %p = transform.num_associations %results : (!transform.any_value) -> !transform.param<i64>
    // expected-remark @below {{2}}
    transform.debug.emit_param_as_remark %p : !transform.param<i64>
    transform.yield
  }
}

// -----

// expected-note @below {{target value}}
func.func @get_result_of_op_bbarg(%arg0: index, %arg1: index) -> index {
  %r = arith.addi %arg0, %arg1 : index
  return %r : index
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
    %addi = transform.structured.match ops{["arith.addi"]} in %arg1 : (!transform.any_op) -> !transform.any_op
    %bbarg = transform.test_produce_value_handle_to_argument_of_parent_block %addi, 0 : (!transform.any_op) -> !transform.any_value
    // expected-error @below {{cannot get defining op of block argument}}
    %op = transform.get_defining_op %bbarg : (!transform.any_value) -> !transform.any_op
    transform.debug.emit_remark_at %op, "matched" : !transform.any_op
    transform.yield
  }
}

// -----

module @named_inclusion attributes { transform.with_named_sequence } {

  transform.named_sequence @foo(%arg0: !transform.any_op {transform.readonly}) -> () {
    // expected-remark @below {{applying transformation "a"}}
    transform.test_transform_op "a"
    transform.yield
  }

  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    transform.include @foo failures(propagate) (%arg0) : (!transform.any_op) -> ()
    transform.yield
  }
}

// -----

module @named_inclusion_in_named attributes { transform.with_named_sequence } {

  transform.named_sequence @foo(%arg0: !transform.any_op {transform.readonly}) -> () {
    // expected-remark @below {{applying transformation "a"}}
    transform.test_transform_op "a"
    transform.yield
  }

  transform.named_sequence @bar(%arg0: !transform.any_op {transform.readonly}) -> () {
    // expected-remark @below {{applying transformation "b"}}
    transform.test_transform_op "b"
    transform.include @foo failures(propagate) (%arg0) : (!transform.any_op) -> ()
    transform.yield
  }

  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    transform.include @bar failures(suppress) (%arg0) : (!transform.any_op) -> ()
    transform.yield
  }
}

// -----

// expected-remark @below {{operation}}
module @named_operands attributes { transform.with_named_sequence } {

  transform.named_sequence @foo(%arg0: !transform.any_op {transform.readonly},
                                %arg1: !transform.any_value {transform.readonly}) -> () {
    transform.debug.emit_remark_at %arg0, "operation" : !transform.any_op
    transform.debug.emit_remark_at %arg1, "value" : !transform.any_value
    transform.yield
  }

  // expected-remark @below {{value}}
  // expected-note @below {{value handle points to a block argument #0 in block #0 in region #0}}
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    %0 = transform.test_produce_value_handle_to_self_operand %arg0 : (!transform.any_op) -> !transform.any_value
    transform.include @foo failures(propagate) (%arg0, %0) : (!transform.any_op, !transform.any_value) -> ()
    transform.yield
  }
}

// -----

// expected-remark @below {{operation}}
module @named_return attributes { transform.with_named_sequence } {

  // expected-remark @below {{value}}
  // expected-note @below {{value handle points to a block argument #0 in block #0 in region #0}}
  transform.named_sequence @foo(%arg0: !transform.any_op {transform.readonly}) -> (!transform.any_op, !transform.any_value) {
    %0 = transform.test_produce_value_handle_to_self_operand %arg0 : (!transform.any_op) -> !transform.any_value
    transform.yield %arg0, %0 : !transform.any_op, !transform.any_value
  }

  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    %0:2 = transform.include @foo failures(propagate) (%arg0) : (!transform.any_op) -> (!transform.any_op, !transform.any_value)
    transform.debug.emit_remark_at %0#0, "operation" : !transform.any_op
    transform.debug.emit_remark_at %0#1, "value" : !transform.any_value
    transform.yield
  }
}

// -----

module attributes { transform.with_named_sequence } {
  transform.named_sequence @match1(%current: !transform.any_op {transform.readonly}) -> (!transform.any_op) {
    transform.test_succeed_if_operand_of_op_kind %current, "test.some_op" : !transform.any_op
    transform.yield %current : !transform.any_op
  }

  transform.named_sequence @match2(%current: !transform.any_op {transform.readonly}) -> (!transform.any_op) {
    transform.test_succeed_if_operand_of_op_kind %current, "func.func" : !transform.any_op
    transform.yield %current : !transform.any_op
  }

  transform.named_sequence @action1(%current: !transform.any_op {transform.readonly}) {
    transform.debug.emit_remark_at %current, "matched1" : !transform.any_op
    transform.yield
  }
  transform.named_sequence @action2(%current: !transform.any_op {transform.readonly}) {
    transform.debug.emit_remark_at %current, "matched2" : !transform.any_op
    transform.yield
  }

  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.foreach_match in %root
        @match1 -> @action1,
        @match2 -> @action2
      : (!transform.any_op) -> (!transform.any_op)
    transform.yield
  }

  // expected-remark @below {{matched2}}
  func.func private @foo()
  // expected-remark @below {{matched2}}
  func.func private @bar()
  "test.testtest"() : () -> ()
  // expected-remark @below {{matched1}}
  "test.some_op"() : () -> ()
}

// -----

module attributes { transform.with_named_sequence } {
  transform.named_sequence @match(!transform.any_op {transform.readonly})
  transform.named_sequence @action()

  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    // expected-error @below {{unresolved external symbol @match}}
    transform.foreach_match in %root
      @match -> @action : (!transform.any_op) -> !transform.any_op
    transform.yield
  }
}

// -----

module attributes { transform.with_named_sequence } {
  transform.named_sequence @match(%arg: !transform.any_op {transform.readonly}) {
    transform.yield
  }
  transform.named_sequence @action()

  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    // expected-error @below {{unresolved external symbol @action}}
    transform.foreach_match in %root
      @match -> @action : (!transform.any_op) -> !transform.any_op
    transform.yield
  }
}

// -----

module attributes { transform.with_named_sequence } {
  transform.named_sequence @match(%arg: !transform.any_op {transform.readonly}) {
    // expected-error @below {{expected operations in the match part to implement MatchOpInterface}}
    "test.unknown_op"() : () -> ()
    transform.yield
  }
  transform.named_sequence @action() {
    transform.yield
  }

  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.foreach_match in %root
      @match -> @action : (!transform.any_op) -> !transform.any_op
    transform.yield
  }
}

// -----

module attributes { transform.with_named_sequence } {
  transform.named_sequence @match_func(%arg0: !transform.any_op {transform.readonly})
    -> !transform.any_op {
    transform.match.operation_name %arg0 ["func.func"] : !transform.any_op
    transform.yield %arg0 : !transform.any_op
  }

  transform.named_sequence @print_func(%arg0: !transform.any_op {transform.readonly}) {
    transform.debug.emit_remark_at %arg0, "matched func" : !transform.any_op
    transform.yield
  }

  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    transform.foreach_match in %arg0 @match_func -> @print_func : (!transform.any_op) -> !transform.any_op
    transform.yield
  }

  // expected-remark @below {{matched func}}
  func.func @payload() {
    return
  }

  // expected-remark @below {{matched func}}
  func.func private @declaration()

  "test.something_else"() : () -> ()
}

// -----

module attributes { transform.with_named_sequence } {
  transform.named_sequence @eq_1(%arg0: !transform.any_op {transform.readonly})
    -> !transform.any_op {
    transform.match.operation_name %arg0 ["func.func"] : !transform.any_op
    %0 = transform.test_produce_param_with_number_of_test_ops %arg0 : !transform.any_op
    %1 = transform.param.constant 1 : i32 -> !transform.test_dialect_param
    transform.match.param.cmpi eq %0, %1 : !transform.test_dialect_param
    transform.debug.emit_remark_at %arg0, "matched == 1" : !transform.any_op
    transform.yield %arg0 : !transform.any_op
  }

  transform.named_sequence @ne_0(%arg0: !transform.any_op {transform.readonly})
    -> !transform.any_op {
    transform.match.operation_name %arg0 ["func.func"] : !transform.any_op
    %0 = transform.test_produce_param_with_number_of_test_ops %arg0 : !transform.any_op
    %1 = transform.param.constant 0 : i32 -> !transform.test_dialect_param
    transform.match.param.cmpi ne %0, %1 : !transform.test_dialect_param
    transform.debug.emit_remark_at %arg0, "matched != 0" : !transform.any_op
    transform.yield %arg0 : !transform.any_op
  }

  transform.named_sequence @gt_m1(%arg0: !transform.any_op {transform.readonly})
    -> !transform.any_op {
    transform.match.operation_name %arg0 ["func.func"] : !transform.any_op
    %0 = transform.test_produce_param_with_number_of_test_ops %arg0 : !transform.any_op
    %1 = transform.param.constant -1 : i32 -> !transform.test_dialect_param
    transform.match.param.cmpi gt %0, %1 : !transform.test_dialect_param
    transform.debug.emit_remark_at %arg0, "matched > -1" : !transform.any_op
    transform.yield %arg0 : !transform.any_op
  }

  transform.named_sequence @ge_1(%arg0: !transform.any_op {transform.readonly})
    -> !transform.any_op {
    transform.match.operation_name %arg0 ["func.func"] : !transform.any_op
    %0 = transform.test_produce_param_with_number_of_test_ops %arg0 : !transform.any_op
    %1 = transform.param.constant 1 : i32 -> !transform.test_dialect_param
    transform.match.param.cmpi ge %0, %1 : !transform.test_dialect_param
    transform.debug.emit_remark_at %arg0, "matched >= 1" : !transform.any_op
    transform.yield %arg0 : !transform.any_op
  }

  transform.named_sequence @lt_1(%arg0: !transform.any_op {transform.readonly})
    -> !transform.any_op {
    transform.match.operation_name %arg0 ["func.func"] : !transform.any_op
    %0 = transform.test_produce_param_with_number_of_test_ops %arg0 : !transform.any_op
    %1 = transform.param.constant 1 : i32 -> !transform.test_dialect_param
    transform.match.param.cmpi lt %0, %1 : !transform.test_dialect_param
    transform.debug.emit_remark_at %arg0, "matched < 1" : !transform.any_op
    transform.yield %arg0 : !transform.any_op
  }

  transform.named_sequence @le_1(%arg0: !transform.any_op {transform.readonly})
    -> !transform.any_op {
    transform.match.operation_name %arg0 ["func.func"] : !transform.any_op
    %0 = transform.test_produce_param_with_number_of_test_ops %arg0 : !transform.any_op
    %1 = transform.param.constant 1 : i32 -> !transform.test_dialect_param
    transform.match.param.cmpi le %0, %1 : !transform.test_dialect_param
    transform.debug.emit_remark_at %arg0, "matched <= 1" : !transform.any_op
    transform.yield %arg0 : !transform.any_op
  }

  transform.named_sequence @do_nothing(%arg0: !transform.any_op {transform.readonly}) {
    transform.yield
  }

  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    %0 = transform.foreach_match in %arg0 @eq_1 -> @do_nothing : (!transform.any_op) -> !transform.any_op
    %1 = transform.foreach_match in %0 @ne_0 -> @do_nothing : (!transform.any_op) -> !transform.any_op
    %2 = transform.foreach_match in %1 @gt_m1 -> @do_nothing : (!transform.any_op) -> !transform.any_op
    %3 = transform.foreach_match in %2 @ge_1 -> @do_nothing : (!transform.any_op) -> !transform.any_op
    %4 = transform.foreach_match in %3 @lt_1 -> @do_nothing : (!transform.any_op) -> !transform.any_op
    %5 = transform.foreach_match in %4 @le_1 -> @do_nothing : (!transform.any_op) -> !transform.any_op
    transform.yield
  }

  // expected-remark @below {{matched > -1}}
  // expected-remark @below {{matched < 1}}
  // expected-remark @below {{matched <= 1}}
  func.func private @declaration()

  // expected-remark @below {{matched == 1}}
  // expected-remark @below {{matched != 0}}
  // expected-remark @below {{matched > -1}}
  // expected-remark @below {{matched >= 1}}
  // expected-remark @below {{matched <= 1}}
  func.func @definition() {
    "test.something"() : () -> ()
    return
  }
}

// -----

// CHECK-LABEL: func @test_tracked_rewrite() {
//  CHECK-NEXT:   transform.test_dummy_payload_op  {new_op} : () -> i1
//  CHECK-NEXT:   transform.test_dummy_payload_op  {new_op} : () -> i1
//  CHECK-NEXT:   return
//  CHECK-NEXT: }
func.func @test_tracked_rewrite() {
  %0 = transform.test_dummy_payload_op {replace_me} : () -> (i1)
  %1 = transform.test_dummy_payload_op {erase_me} : () -> (i1)
  %2 = transform.test_dummy_payload_op {replace_me} : () -> (i1)
  func.return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
    %0 = transform.structured.match ops{["transform.test_dummy_payload_op"]} in %arg1 : (!transform.any_op) -> !transform.any_op
    // expected-remark @below {{2 iterations}}
    transform.test_tracked_rewrite %0 : (!transform.any_op) -> ()
    // One replacement op (test.drop_mapping) is dropped from the mapping.
    %p = transform.num_associations %0 : (!transform.any_op) -> !transform.param<i64>
    // expected-remark @below {{2}}
    transform.debug.emit_param_as_remark  %p : !transform.param<i64>
    transform.yield
  }
}

// -----

// Parameter deduplication happens by value

module attributes {transform.with_named_sequence} {

  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    %1 = transform.param.constant 1 -> !transform.param<i64>
    %2 = transform.param.constant 1 -> !transform.param<i64>
    %3 = transform.param.constant 2 -> !transform.param<i64>
    %4 = transform.merge_handles %1, %2 { deduplicate } : !transform.param<i64>
    %p = transform.num_associations %4 : (!transform.param<i64>) -> !transform.param<i64>
    // expected-remark @below {{1}}
    transform.debug.emit_param_as_remark %p : !transform.param<i64>

    %5 = transform.merge_handles %1, %1 { deduplicate } : !transform.param<i64>
    %p2 = transform.num_associations %5 : (!transform.param<i64>) -> !transform.param<i64>
    // expected-remark @below {{1}}
    transform.debug.emit_param_as_remark %p2 : !transform.param<i64>

    %6 = transform.merge_handles %1, %3 { deduplicate } : !transform.param<i64>
    %p3 = transform.num_associations %6 : (!transform.param<i64>) -> !transform.param<i64>
    // expected-remark @below {{2}}
    transform.debug.emit_param_as_remark %p3 : !transform.param<i64>

    %7 = transform.merge_handles %1, %1, %2, %3 : !transform.param<i64>
    %p4 = transform.num_associations %7 : (!transform.param<i64>) -> !transform.param<i64>
    // expected-remark @below {{4}}
    transform.debug.emit_param_as_remark %p4 : !transform.param<i64>
    transform.yield
  }
}

// -----

%0:3 = "test.get_two_results"() : () -> (i32, i32, f32)

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    %1 = transform.structured.match ops{["test.get_two_results"]} in %arg0 : (!transform.any_op) -> !transform.any_op
    %2 = transform.test_produce_value_handle_to_result %1, 0 : (!transform.any_op) -> !transform.any_value
    %3 = transform.test_produce_value_handle_to_result %1, 1 : (!transform.any_op) -> !transform.any_value

    %4 = transform.merge_handles %2, %2 { deduplicate } : !transform.any_value
    %p = transform.num_associations %4 : (!transform.any_value) -> !transform.param<i64>
    // expected-remark @below {{1}}
    transform.debug.emit_param_as_remark %p : !transform.param<i64>

    %5 = transform.merge_handles %2, %3 { deduplicate } : !transform.any_value
    %p2 = transform.num_associations %5 : (!transform.any_value) -> !transform.param<i64>
    // expected-remark @below {{2}}
    transform.debug.emit_param_as_remark %p2 : !transform.param<i64>

    %6 = transform.test_produce_value_handle_to_result %1, 0 : (!transform.any_op) -> !transform.any_value
    %7 = transform.merge_handles %2, %6 { deduplicate } : !transform.any_value
    %p3 = transform.num_associations %6 : (!transform.any_value) -> !transform.param<i64>
    // expected-remark @below {{1}}
    transform.debug.emit_param_as_remark %p3 : !transform.param<i64>

    %8 = transform.merge_handles %2, %2, %3, %4 : !transform.any_value
    %p4 = transform.num_associations %8 : (!transform.any_value) -> !transform.param<i64>
    // expected-remark @below {{4}}
    transform.debug.emit_param_as_remark %p4 : !transform.param<i64>
    transform.yield
  }
}
// -----

// CHECK-LABEL: func @test_annotation()
//  CHECK-NEXT:   "test.annotate_me"()
//  CHECK-SAME:                        any_attr = "example"
//  CHECK-SAME:                        broadcast_attr = 2 : i64
//  CHECK-SAME:                        new_attr = 1 : i32
//  CHECK-SAME:                        unit_attr
//  CHECK-NEXT:   "test.annotate_me"()
//  CHECK-SAME:                        any_attr = "example"
//  CHECK-SAME:                        broadcast_attr = 2 : i64
//  CHECK-SAME:                        existing_attr = "test"
//  CHECK-SAME:                        new_attr = 1 : i32
//  CHECK-SAME:                        unit_attr
//  CHECK-NEXT:   "test.annotate_me"()
//  CHECK-SAME:                        any_attr = "example"
//  CHECK-SAME:                        broadcast_attr = 2 : i64
//  CHECK-SAME:                        new_attr = 1 : i32
//  CHECK-SAME:                        unit_attr
func.func @test_annotation() {
  %0 = "test.annotate_me"() : () -> (i1)
  %1 = "test.annotate_me"() {existing_attr = "test"} : () -> (i1)
  %2 = "test.annotate_me"() {new_attr = 0} : () -> (i1)
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    %0 = transform.structured.match ops{["test.annotate_me"]} in %arg0 : (!transform.any_op) -> !transform.any_op
    %1 = transform.test_produce_param_with_number_of_test_ops %0 : !transform.any_op
    transform.annotate %0 "new_attr" = %1 : !transform.any_op, !transform.test_dialect_param

    %2 = transform.param.constant 2 -> !transform.param<i64>
    transform.annotate %0 "broadcast_attr" = %2 : !transform.any_op, !transform.param<i64>
    transform.annotate %0 "unit_attr" : !transform.any_op

    %3 = transform.param.constant "example" -> !transform.any_param
    transform.annotate %0 "any_attr" = %3 : !transform.any_op, !transform.any_param
    transform.yield
  }
}

// -----

func.func @notify_payload_op_replaced(%arg0: index, %arg1: index) {
  %0 = arith.muli %arg0, %arg1 {original} : index
  // expected-remark @below{{updated handle}}
  %1 = arith.muli %arg0, %arg1 {replacement} : index
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
    %0 = transform.structured.match attributes{original} in %arg1 : (!transform.any_op) -> !transform.any_op
    %1 = transform.structured.match attributes{replacement} in %arg1 : (!transform.any_op) -> !transform.any_op
    transform.test_notify_payload_op_replaced %0, %1 : (!transform.any_op, !transform.any_op) -> ()
    transform.debug.emit_remark_at %0, "updated handle" : !transform.any_op
    transform.yield
  }
}

// -----

// CHECK-LABEL: func @test_apply_cse()
//       CHECK:   %[[const:.*]] = arith.constant 0 : index
//       CHECK:   %[[ex1:.*]] = scf.execute_region -> index {
//       CHECK:     scf.yield %[[const]]
//       CHECK:   }
//       CHECK:   %[[ex2:.*]] = scf.execute_region -> index {
//       CHECK:     scf.yield %[[const]]
//       CHECK:   }
//       CHECK:   return %[[const]], %[[ex1]], %[[ex2]]
func.func @test_apply_cse() -> (index, index, index) {
  // expected-remark @below{{eliminated 1}}
  // expected-remark @below{{eliminated 2}}
  %0 = arith.constant 0 : index
  %1 = scf.execute_region -> index {
    %2 = arith.constant 0 : index
    scf.yield %2 : index
  } {first}
  %3 = scf.execute_region -> index {
    %4 = arith.constant 0 : index
    scf.yield %4 : index
  } {second}
  return %0, %1, %3 : index, index, index
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
    %0 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op
    %first = transform.structured.match attributes{first} in %0 : (!transform.any_op) -> !transform.any_op
    %elim_first = transform.structured.match ops{["arith.constant"]} in %first : (!transform.any_op) -> !transform.any_op
    %second = transform.structured.match attributes{first} in %0 : (!transform.any_op) -> !transform.any_op
    %elim_second = transform.structured.match ops{["arith.constant"]} in %first : (!transform.any_op) -> !transform.any_op

    // There are 3 arith.constant ops.
    %all = transform.structured.match ops{["arith.constant"]} in %0 : (!transform.any_op) -> !transform.any_op
    %p = transform.num_associations %all : (!transform.any_op) -> !transform.param<i64>
    // expected-remark @below{{3}}
    transform.debug.emit_param_as_remark %p : !transform.param<i64>
    // "deduplicate" has no effect because these are 3 different ops.
    %merged_before = transform.merge_handles deduplicate %all : !transform.any_op
    %p2 = transform.num_associations %merged_before : (!transform.any_op) -> !transform.param<i64>
    // expected-remark @below{{3}}
    transform.debug.emit_param_as_remark %p2 : !transform.param<i64>

    // Apply CSE.
    transform.apply_cse to %0 : !transform.any_op

    // The handle is still mapped to 3 arith.constant ops.
    %p3 = transform.num_associations %all : (!transform.any_op) -> !transform.param<i64>
    // expected-remark @below{{3}}
    transform.debug.emit_param_as_remark %p3 : !transform.param<i64>
    // But they are all the same op.
    %merged_after = transform.merge_handles deduplicate %all : !transform.any_op
    %p4 = transform.num_associations %merged_after : (!transform.any_op) -> !transform.param<i64>
    // expected-remark @below{{1}}
    transform.debug.emit_param_as_remark %p4 : !transform.param<i64>

    // The other handles were also updated.
    transform.debug.emit_remark_at %elim_first, "eliminated 1" : !transform.any_op
    %p5 = transform.num_associations %elim_first : (!transform.any_op) -> !transform.param<i64>
    // expected-remark @below{{1}}
    transform.debug.emit_param_as_remark %p5 : !transform.param<i64>
    transform.debug.emit_remark_at %elim_second, "eliminated 2" : !transform.any_op
    %p6 = transform.num_associations %elim_second : (!transform.any_op) -> !transform.param<i64>
    // expected-remark @below{{1}}
    transform.debug.emit_param_as_remark %p6 : !transform.param<i64>
    transform.yield
  }
}

// -----

// CHECK-LABEL: func @test_licm(
//       CHECK:   arith.muli
//       CHECK:   scf.for {{.*}} {
//       CHECK:     vector.print
//       CHECK:   }
func.func @test_licm(%arg0: index, %arg1: index, %arg2: index) {
  scf.for %iv = %arg0 to %arg1 step %arg2 {
    %0 = arith.muli %arg0, %arg1 : index
    vector.print %0 : index
  }
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
    %0 = transform.structured.match ops{["scf.for"]} in %arg1 : (!transform.any_op) -> !transform.any_op
    transform.apply_licm to %0 : !transform.any_op
    transform.yield
  }
}

// -----

// expected-note @below{{when applied to this op}}
module attributes {transform.with_named_sequence} {
  func.func @test_licm_invalid() {
    return
  }

  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
    // expected-error @below{{transform applied to the wrong op kind}}
    transform.apply_licm to %arg1 : !transform.any_op
    transform.yield
  }
}

// -----

func.func @get_parent_op() {
  // expected-remark @below{{found test.foo parent}}
  "test.foo"() ({
    // expected-remark @below{{direct parent}}
    "test.bar"() ({
      "test.qux"() : () -> ()
      "test.qux"() : () -> ()
    }) : () -> ()
  }) : () -> ()
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
    %0 = transform.structured.match ops{["test.qux"]} in %arg1 : (!transform.any_op) -> !transform.any_op

    // Get parent by name.
    %1 = transform.get_parent_op %0 {op_name = "test.foo"} : (!transform.any_op) -> !transform.any_op
    transform.debug.emit_remark_at %1, "found test.foo parent" : !transform.any_op

    // Get immediate parent.
    %2 = transform.get_parent_op %0 : (!transform.any_op) -> !transform.any_op
    transform.debug.emit_remark_at %2, "direct parent" : !transform.any_op
    %p = transform.num_associations %2 : (!transform.any_op) -> !transform.param<i64>
    // expected-remark @below{{2}}
    transform.debug.emit_param_as_remark %p : !transform.param<i64>

    // Deduplicate results.
    %3 = transform.structured.match ops{["test.qux"]} in %arg1 : (!transform.any_op) -> !transform.any_op
    %4 = transform.get_parent_op %3 {deduplicate} : (!transform.any_op) -> !transform.any_op
    %p2 = transform.num_associations %4 : (!transform.any_op) -> !transform.param<i64>
    // expected-remark @below{{1}}
    transform.debug.emit_param_as_remark %p2 : !transform.param<i64>
    transform.yield
  }
}


// -----

// expected-note @below {{target op}}
module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    // expected-error @below{{could not find a parent op that matches all requirements}}
    %3 = transform.get_parent_op %arg0 {op_name = "builtin.module"} : (!transform.any_op) -> !transform.any_op
    transform.yield
  }
}

// -----

func.func @cast(%arg0: f32) -> f64 {
  // expected-remark @below{{f64}}
  %0 = arith.extf %arg0 : f32 to f64
  return %0 : f64
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    %0 = transform.structured.match ops{["arith.extf"]} in %arg0 : (!transform.any_op) -> !transform.op<"arith.extf">
    %1 = transform.get_result %0[0] : (!transform.op<"arith.extf">) -> !transform.any_value
    %2 = transform.get_type %1 : (!transform.any_value) -> !transform.type
    transform.debug.emit_param_as_remark %2 at %0 : !transform.type, !transform.op<"arith.extf">
    transform.yield
  }
}

// -----

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    // expected-error @below {{expected type attribute, got 0 : i32}}
    transform.test_produce_param (0 : i32) : !transform.type
    transform.yield
  }
}

// -----

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    // expected-error @below {{expected affine map attribute, got 0 : i32}}
    transform.test_produce_param (0 : i32) : !transform.affine_map
    transform.yield
  }
}

// -----

// CHECK-LABEL: @type_param_anchor
func.func private @type_param_anchor()

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    // CHECK: test_produce_param(f32) : !transform.type
    transform.test_produce_param(f32) : !transform.type
    transform.yield
  }
}

// -----

// CHECK-LABEL: @affine_map_param_anchor
func.func private @affine_map_param_anchor()

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    // CHECK: test_produce_param(#{{.*}}) : !transform.affine_map
    transform.test_produce_param(affine_map<(d0) -> ()>) : !transform.affine_map
    transform.yield
  }
}

// -----

func.func @verify_success(%arg0: f64) -> f64 {
  return %arg0 : f64
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    %0 = transform.structured.match ops{["func.func"]} in %arg0 : (!transform.any_op) -> !transform.any_op
    transform.verify %0 : !transform.any_op
    transform.yield
  }
}

// -----

// expected-error @below{{fail_to_verify is set}}
// expected-note @below{{payload op}}
func.func @verify_failure(%arg0: f64) -> f64 {
  return %arg0 : f64
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    %0 = transform.structured.match ops{["func.func"]} in %arg0 : (!transform.any_op) -> !transform.any_op
    transform.test_produce_invalid_ir %0 : !transform.any_op
    // expected-error @below{{failed to verify payload op}}
    transform.verify %0 : !transform.any_op
    transform.yield
  }
}

// -----

func.func @select() {
  // expected-remark @below{{found foo}}
  "test.foo"() : () -> ()
  // expected-remark @below{{found bar}}
  "test.bar"() : () -> ()
  // expected-remark @below{{found foo}}
  "test.foo"() : () -> ()
  func.return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    // Match all ops inside the function (including the function itself).
    %func_op = transform.structured.match ops{["func.func"]} in %arg0 : (!transform.any_op) -> !transform.any_op
    %0 = transform.structured.match in %func_op : (!transform.any_op) -> !transform.any_op
    %p = transform.num_associations %0 : (!transform.any_op) -> !transform.param<i64>
    // expected-remark @below{{5}}
    transform.debug.emit_param_as_remark %p : !transform.param<i64>

    // Select "test.foo".
    %foo = transform.select "test.foo" in %0 : (!transform.any_op) -> !transform.any_op
    transform.debug.emit_remark_at %foo, "found foo" : !transform.any_op

    // Select "test.bar".
    %bar = transform.select "test.bar" in %0 : (!transform.any_op) -> !transform.any_op
    transform.debug.emit_remark_at %bar, "found bar" : !transform.any_op
    transform.yield
  }
}

// -----

// CHECK-LABEL: func @apply_dce(
//  CHECK-NEXT:   memref.store
//  CHECK-NEXT:   return
func.func @apply_dce(%f: f32, %m: memref<5xf32>, %idx: index) {
  // Two dead ops, interleaved with a non-dead op.
  %0 = tensor.empty() : tensor<5xf32>
  memref.store %f, %m[%idx] : memref<5xf32>
  %1 = tensor.insert %f into %0[%idx] : tensor<5xf32>
  return
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    %func_op = transform.structured.match ops{["func.func"]} in %arg0 : (!transform.any_op) -> !transform.any_op
    %empty_op = transform.structured.match ops{["tensor.empty"]} in %func_op : (!transform.any_op) -> !transform.any_op
    transform.apply_dce to %func_op : !transform.any_op

    %p = transform.num_associations %empty_op : (!transform.any_op) -> !transform.param<i64>
    // expected-remark @below{{0}}
    transform.debug.emit_param_as_remark %p : !transform.param<i64>
    transform.yield
  }
}


// -----

func.func @no_constant_under_loop(%lb: index, %ub: index, %step: index) {
  scf.for %i= %lb to %ub step %step {
    arith.constant 0 : index
  }
  return
}

module @named_inclusion attributes { transform.with_named_sequence } {
// Match `arith.constant`s that are not nested under a `scf.for` and ensure
// there are none in the program

  transform.named_sequence @print(%root: !transform.any_op {transform.readonly}) {
    transform.debug.emit_remark_at %root, "matched func" : !transform.any_op
    transform.yield
  }

  transform.named_sequence @match_constant_not_under_scf_for(%root: !transform.any_op {transform.readonly})
    -> !transform.any_op {
    transform.match.operation_name %root ["arith.constant"] : !transform.any_op
    %for = transform.get_parent_op %root { op_name = "scf.for", allow_empty_results }
      : (!transform.any_op) -> (!transform.any_op)
    transform.match.operation_empty %for : !transform.any_op
    transform.yield %root : !transform.any_op
  }

  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    transform.foreach_match in %arg0
        @match_constant_not_under_scf_for -> @print
      : (!transform.any_op) -> (!transform.any_op)
    transform.yield
  }
}

// -----

func.func @no_constant_under_loop(%lb: index, %ub: index, %step: index) {
  // expected-remark @below {{no parent scf.for}}
  arith.constant 0 : index
  return
}

module @named_inclusion attributes { transform.with_named_sequence } {
  // Match `arith.constant`s that are not nested under a `scf.for` and ensure
  // there are none in the program

  transform.named_sequence @print(%root: !transform.any_op {transform.readonly}) {
    transform.debug.emit_remark_at %root, "no parent scf.for" : !transform.any_op
    transform.yield
  }

  transform.named_sequence @match_constant_not_under_scf_for(%root: !transform.any_op {transform.readonly})
    -> !transform.any_op {
    transform.match.operation_name %root ["arith.constant"] : !transform.any_op
    %for = transform.get_parent_op %root { op_name = "scf.for", allow_empty_results }
      : (!transform.any_op) -> (!transform.any_op)
    transform.match.operation_empty %for : !transform.any_op
    transform.yield %root : !transform.any_op
  }

  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    transform.foreach_match in %arg0
        @match_constant_not_under_scf_for -> @print
      : (!transform.any_op) -> (!transform.any_op)
    transform.yield
  }
}

// -----

module attributes { transform.with_named_sequence } {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    // expected-error @below {{result #0, associated with 2 payload objects, expected 1}}
    transform.collect_matching @matcher in %arg0 : (!transform.any_op) -> !transform.any_op
    transform.yield
  }

  transform.named_sequence @matcher(%arg0: !transform.any_op {transform.readonly}) -> !transform.any_op {
    %0 = transform.merge_handles %arg0, %arg0 : !transform.any_op
    transform.yield %0 : !transform.any_op
  }
}

// -----

module attributes { transform.with_named_sequence } {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    // expected-error @below {{unresolved external symbol @matcher}}
    transform.collect_matching @matcher in %arg0 : (!transform.any_op) -> !transform.any_op
    transform.yield
  }

  transform.named_sequence @matcher(%arg0: !transform.any_op {transform.readonly}) -> !transform.any_op
}

// -----

module attributes { transform.with_named_sequence } {
  transform.named_sequence @__transform_main(%arg0: !transform.any_op) {
    // expected-remark @below {{matched}}
    %0 = transform.collect_matching @matcher in %arg0 : (!transform.any_op) -> !transform.any_op
    // expected-remark @below {{matched}}
    transform.debug.emit_remark_at %0, "matched" : !transform.any_op
    transform.yield
  }

  transform.named_sequence @matcher(%arg0: !transform.any_op {transform.readonly}) -> !transform.any_op {
    transform.match.operation_name %arg0 ["transform.debug.emit_remark_at", "transform.collect_matching"] : !transform.any_op
    transform.yield %arg0 : !transform.any_op
  }
}
